import { RoomSafeState } from '@/room/state/types'
import { DpHarvestTask } from './types'
import { dpHarvesterWork, spawnDpHarvester } from './dpHarvester'
import { getCreeps } from '@/modules/structures/spawn'
import { dpCarrierWork, spawnDpCarrier } from './dpCarrier'
import { ObserveTask } from '../observe/types'
import { defineGlobalProperty, generateId, isInterval, isMyRoom, isOfficialShard, log, roomNameToXY } from '@/ayaka'
import { getFreeSpace, serializePos } from '@/utils/position'
import ObserveTaskManager from '../observe'

/**
 * 沉积物采集任务管理器
 */
export default class DpHarvestTaskManager {
    /**
     * 运行
     */
    public static run(room: MyRoom) {
        DpHarvestTaskManager.scoutCrossRoom(room)

        const memory = DpHarvestTaskManager.getMemory(room)
        const { tasks } = memory
        tasks.forEach((task, index) => {
            const dpHarvesters = getCreeps(room, task.harvesters)
            const dpCarriers = getCreeps(room, task.carriers)

            if (task.done && !dpHarvesters.length && !dpCarriers.length) {
                DpHarvestTaskManager.removeTask(room, task.id)
                return
            }

            // 一次性只处理 3 个任务
            if (index >= 3) return

            // 孵化相关
            if (
                !task.done &&
                room.memory.state.safe?.state === RoomSafeState.normal &&
                (!task.restartTime || task.restartTime <= Game.time)
            ) {
                spawnDpHarvester(room, task, dpHarvesters)
                spawnDpCarrier(room, task, dpHarvesters, dpCarriers)
            }

            dpHarvesterWork(room, task, dpHarvesters)
            dpCarrierWork(room, task, dpHarvesters, dpCarriers)
        })
    }

    /**
     * 获取 memory
     */
    public static getMemory(room: Room) {
        if (!room.memory.dpHarvest) {
            room.memory.dpHarvest = {
                rooms: [],
                tasks: [],
            }
        }
        return room.memory.dpHarvest
    }

    /**
     * 是否值得挖
     */
    public static isWorthy(deposit: Deposit) {
        return deposit.lastCooldown < 40 && deposit.ticksToDecay > 6000
    }

    /**
     * 添加任务
     */
    public static addTask(room: Room, task: DpHarvestTask) {
        const memory = DpHarvestTaskManager.getMemory(room)
        memory.tasks.push(task)
        log(`沉积物${task.depositType}添加成功，位置：${task.posStr}`, ['dpHarvest'], 'green')
    }

    /**
     * 移除任务
     */
    public static removeTask(room: Room, id: string) {
        const memory = DpHarvestTaskManager.getMemory(room)
        const index = memory.tasks.findIndex((task) => task.id === id)
        if (index >= 0) {
            memory.tasks.splice(index, 1)
        }
    }

    /**
     * 查找指定 depositId 的任务
     */
    public static findTaskByDepositId(room: Room, depositId: string) {
        const memory = DpHarvestTaskManager.getMemory(room)
        return memory.tasks.find((task) => task.depositId === depositId)
    }

    /**
     * 添加过道房间
     */
    public static addRoom(myRoomName: string, roomName: string | string[]) {
        const room = Game.rooms[myRoomName]
        if (!isMyRoom(room)) return false
        const memory = DpHarvestTaskManager.getMemory(room)
        if (typeof roomName === 'string') {
            roomName = [roomName]
        }
        memory.rooms = [...new Set([...memory.rooms, ...roomName])].sort((a, b) => {
            const [ax, ay] = roomNameToXY(a)
            const [bx, by] = roomNameToXY(b)
            return ax - bx || ay - by
        })
        return true
    }

    /**
     * 移除过道房间
     */
    public static removeRoom(myRoomName: string, roomName: string | string[]) {
        const room = Game.rooms[myRoomName]
        if (!isMyRoom(room)) return false
        const memory = DpHarvestTaskManager.getMemory(room)
        if (typeof roomName === 'string') {
            roomName = [roomName]
        }
        memory.rooms = memory.rooms.filter((name) => !roomName.includes(name))
        return true
    }

    /**
     * 查看过道房间
     */
    public static viewRooms(myRoomName: string) {
        const room = Game.rooms[myRoomName]
        if (!isMyRoom(room)) return
        const memory = DpHarvestTaskManager.getMemory(room)
        return memory.rooms
    }

    /**
     * 侦察过道房间
     */
    protected static scoutCrossRoom(room: MyRoom, force = false) {
        if (!isInterval(631) && !force) return

        if (!room.storage) return

        if (isOfficialShard()) {
            // 官服暂时不开启
            return
        }

        const memory = DpHarvestTaskManager.getMemory(room)
        const { rooms } = memory
        if (!rooms.length) return

        if (room.memory.state.safe?.state !== RoomSafeState.normal) return

        if (ObserveTaskManager.getTaskByName(room, `dpHarvest_${room.name}`)) return
        DpHarvestTaskManager.addObserveTask(room, rooms)
    }

    /**
     * 添加过道房间观察任务
     */
    public static addObserveTask(room: MyRoom, rooms: string[], force = false) {
        ObserveTaskManager.addTask(room, {
            name: `dpHarvest_${room.name}`,
            type: 'dpHarvest',
            roomNames: rooms,
            roomIndex: 0,
            scouts: [],
            data: {
                force,
            },
        })
    }
}

/**
 * 过道房间观察
 */
export const dpHarvestRoomObserver = (creep: Creep, task: ObserveTask) => {
    const myRoom = Game.rooms[creep.memory.belong]
    if (!myRoom || !isMyRoom(myRoom)) {
        task.done = true
        return
    }

    // 寻找 deposit
    const deposits = creep.room
        .find(FIND_DEPOSITS)
        .filter(({ id }) => !DpHarvestTaskManager.findTaskByDepositId(myRoom, id))
    // 存在沉积物，判断是否值得挖，值得就添加任务
    deposits.forEach((deposit) => {
        if (!DpHarvestTaskManager.isWorthy(deposit)) return

        const freePos = getFreeSpace(deposit.pos)
        const dpTask: DpHarvestTask = {
            id: generateId(),
            depositId: deposit.id,
            posStr: serializePos(deposit.pos),
            depositType: deposit.depositType,
            freePos: freePos.length,
            lastCooldown: deposit.lastCooldown,
            ticksToDecay: deposit.ticksToDecay,
            harvesters: [],
            carriers: [],
        }

        DpHarvestTaskManager.addTask(myRoom, dpTask)
    })

    const { roomIndex, roomNames } = task

    // 当前房间不是目标房间
    if (roomNames[roomIndex] !== creep.room.name) {
        return
    }

    if (roomIndex >= roomNames.length - 1) {
        // 翻转房间列表
        roomNames.reverse()
        task.roomIndex = 1
    } else {
        task.roomIndex++
    }
    task.roomNames = [...DpHarvestTaskManager.getMemory(myRoom).rooms]
}

defineGlobalProperty('DpHarvest', {
    value: DpHarvestTaskManager,
})
